﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Compiler
{
    public class EBNF_NodeFactory : INodeFactory
    {
        Dictionary<string, EbnfToken> EbnfTokenDict = new Dictionary<string, EbnfToken>();
        Dictionary<string, EbnfMeta> EbnfMetaDict = new Dictionary<string, EbnfMeta>();
        EbnfEpsilonNode EpsNode = new EbnfEpsilonNode();
        
        public INode OnTerminal(LexerPair lexerPair)
        {
            Symbol terminal = lexerPair.Token.Terminal;

            if (terminal.ID == 0) //token
            {
                string lexeme = lexerPair.Lexeme;
                EbnfToken ebnfToken;
                if (!EbnfTokenDict.TryGetValue(lexeme, out ebnfToken))
                {
                    ebnfToken = new EbnfToken(lexeme);
                    EbnfTokenDict.Add(lexeme, ebnfToken);
                }

                return ebnfToken;
            }

            if (terminal.ID == 1) //meta
            {
                string lexeme = lexerPair.Lexeme;
                EbnfMeta ebnfMeta;
                if (!EbnfMetaDict.TryGetValue(lexeme, out ebnfMeta))
                {
                    ebnfMeta = new EbnfMeta(lexeme);
                    EbnfMetaDict.Add(lexeme, ebnfMeta);
                }

                return ebnfMeta;
            }

            if (terminal.ID == 13)
                return EpsNode;

            if (terminal.ID == 32)
                return new IntegerNode(lexerPair.Lexeme);
                

            return null;
        }

        public INode OnNonterminal(Production production, Stack<INode> nodeStack)
        {
            switch (production.ID)
            {
                case 10: //Program
                    {
                        var child = nodeStack.PopN(2).Cast<INode>().ToList();

                        return new ProgramNode(child[0] is LexEmptyNode ? null : (LexRuleSequence)child[0], (EbnfRuleSequence)child[1]);
                    }
                case 90: //lex-sequence
                    {
                        var child = nodeStack.PopN(2).Cast<LexNode>().ToList();
                        return new LexRuleSequence(child[0], child[1]);
                    }
                case 91:
                    {
                        return new LexEmptyNode();
                    }
                case 92: //lex-assign
                    {
                        var child = nodeStack.PopN(2).Cast<INode>().ToList();
                        return new LexAssign(child[0].To<IntegerNode>(), child[1].To<EbnfToken>(), "");
                    }
                case 101: //ebnf-sequence
                    {
                        var child = nodeStack.PopN(2).Cast<EbnfNode>().ToList();
                        return new EbnfRuleSequence(child[0], child[1]);
                    }
                case 102:
                    {
                        return new EbnfEmptyNode();
                    }
                case 103: //ebnf-assign
                    {
                        var child = nodeStack.PopNodes(3);
                        return new EbnfAssign(child[0].To<IntegerNode>(), child[1].To<EbnfMeta>(), child[2].To<EbnfNode>());
                    }
                case 104: //alternate
                    {
                        var child = nodeStack.PopN(2).Cast<EbnfNode>().ToList();
                        return new EbnfAlternate(child[0], child[1]);
                    }
                case 106: //concat
                    {
                        var child = nodeStack.PopN(2).Cast<EbnfNode>().ToList();
                        return new EbnfConcat(child[0], child[1]);
                    }
                case 108: //[]
                    {
                        //var child = nodeStack.PopN(1).Cast<EbnfNode>().ToList();
                        var child = (EbnfNode)nodeStack.Pop();
                        return new EbnfSquareBracket(child);
                    }
                case 109: //{}
                    {
                        //var child = nodeStack.PopN(1).Cast<EbnfNode>().ToList();
                        var child = (EbnfNode)nodeStack.Pop();
                        return new EbnfCurlyBracket(child);
                    }
                case 111: //<>
                    {
                        var child = (EbnfNode)nodeStack.Pop();
                        return new EbnfAngleBracket(child);
                    }
                default:
                    return null;
            }
        }
    }
}
